xenpaging: handle temporary out-of-memory conditions during page-in
authorKeir Fraser <keir@xen.org>
Fri, 26 Nov 2010 14:23:31 +0000 (14:23 +0000)
committerKeir Fraser <keir@xen.org>
Fri, 26 Nov 2010 14:23:31 +0000 (14:23 +0000)
p2m_mem_paging_prep() should return -ENOMEM if a new page could not be
allocated. This can be handled in xenpaging to retry the
page-in. Right now such condition would stall the guest because the
requested page will not come back, xenpaging simply exits. So
xenpaging could very well retry the allocation forever to rescue the
guest.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
tools/xenpaging/xenpaging.c
xen/arch/x86/mm/p2m.c

index 136f075aa83151d4fee16a28a58a5a1e6ad6c66a..10026612059546b07e104c0bb7bd7d792f85756d 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdarg.h>
 #include <time.h>
 #include <signal.h>
+#include <unistd.h>
 #include <xc_private.h>
 
 #include <xen/mem_event.h>
@@ -415,19 +416,31 @@ static int xenpaging_populate_page(
     unsigned long _gfn;
     void *page;
     int ret;
+    unsigned char oom = 0;
 
-    /* Tell Xen to allocate a page for the domain */
-    ret = xc_mem_paging_prep(paging->xc_handle, paging->mem_event.domain_id,
-                             *gfn);
-    if ( ret != 0 )
+    _gfn = *gfn;
+    do
     {
-        ERROR("Error preparing for page in");
-        goto out_map;
+        /* Tell Xen to allocate a page for the domain */
+        ret = xc_mem_paging_prep(paging->xc_handle, paging->mem_event.domain_id,
+                                 _gfn);
+        if ( ret != 0 )
+        {
+            if ( errno == ENOMEM )
+            {
+                if ( oom++ == 0 )
+                    DPRINTF("ENOMEM while preparing gfn %lx\n", _gfn);
+                sleep(1);
+                continue;
+            }
+            ERROR("Error preparing for page in");
+            goto out_map;
+        }
     }
+    while ( ret && !interrupted );
 
     /* Map page */
     ret = -EFAULT;
-    _gfn = *gfn;
     page = xc_map_foreign_pages(paging->xc_handle, paging->mem_event.domain_id,
                                 PROT_READ | PROT_WRITE, &_gfn, 1);
     *gfn = _gfn;
index 9620866ef3593c46de53f66e112741626a88d91a..d18b3876ae00d1030a92fbe96098e72add922997 100644 (file)
@@ -2802,7 +2802,7 @@ int p2m_mem_paging_prep(struct p2m_domain *p2m, unsigned long gfn)
     /* Get a free page */
     page = alloc_domheap_page(p2m->domain, 0);
     if ( unlikely(page == NULL) )
-        return -EINVAL;
+        return -ENOMEM;
 
     /* Fix p2m mapping */
     p2m_lock(p2m);